package jcolibri.test.recomendador;



import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;

import jcolibri.cbraplications.StandardCBRApplication;
import jcolibri.cbrcore.Attribute;
import jcolibri.cbrcore.CBRCase;
import jcolibri.cbrcore.CBRCaseBase;
import jcolibri.cbrcore.CBRQuery;
import jcolibri.cbrcore.Connector;
import jcolibri.connector.ExtendedDataBaseConnector;
import jcolibri.exception.ExecutionException;
//import jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod;
//import jcolibri.extensions.recommendation.casesDisplay.UserChoice;
import jcolibri.extensions.recommendation.collaborative.CollaborativeRetrievalMethod;
import jcolibri.extensions.recommendation.collaborative.MatrixCaseBase;
import jcolibri.extensions.recommendation.collaborative.PearsonMatrixCaseBase;
//import jcolibri.extensions.recommendation.conditionals.BuyOrQuit;
import jcolibri.method.retrieve.RetrievalResult;

import jcolibri.method.retrieve.NNretrieval.NNConfig;
import jcolibri.method.retrieve.NNretrieval.NNScoringMethod;
import jcolibri.method.retrieve.NNretrieval.similarity.global.Average;
import jcolibri.method.retrieve.NNretrieval.similarity.local.Equal;
import jcolibri.method.retrieve.NNretrieval.similarity.local.Table;
import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaLessIsBetter;
import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaMoreIsBetter;
import jcolibri.method.retrieve.selection.SelectCases;
import jcolibri.test.database.ConfigurableHSQLDBserver;
import jcolibri.test.recomendador.datos.AccesoBBDD;
import jcolibri.test.recomendador.datos.ExtendedExtendedDatabaseConnector;
import jcolibri.test.recomendador.datos.Movie;
import jcolibri.test.recomendador.datos.Rateo;
import jcolibri.test.recomendador.datos.User;
import jcolibri.test.recomendador.datos.IntervaloFechas;
import jcolibri.test.recomendador.Rating;
import jcolibri.test.recomendador.UserIdent;

import jcolibri.test.recomendador.presentacion.Recomendacion;
import jcolibri.test.recomendador.presentacion.Recomendacion;

import jcolibri.test.recomendador.presentacion.Inicio;
import jcolibri.test.recommenders.housesData.HouseDescription;

import jcolibri.test.recomendador.UserChoice;
import jcolibri.test.recomendador.BuyOrQuit;
import jcolibri.test.recomendador.DisplayCasesTableMethod;



public class Recomienda implements StandardCBRApplication {

   private ExtendedExtendedDatabaseConnector _connector;
    /** CaseBase object */
   private PearsonMatrixCaseBase _caseBase;
   private UserIdent u;
   private NNConfig simConfig;
    
    
    static Recomienda recomienda;
        private AccesoBBDD accesoBBDD;
        
        public static Recomienda getInstancia(){
                if (recomienda==null)
                        recomienda=new Recomienda();
                return recomienda;
        }


        @Override
        public void configure() throws ExecutionException {
                 _connector = new ExtendedExtendedDatabaseConnector();
                    // Init the ddbb connector with the config file
                 _connector.initFromXMLfile(jcolibri.util.FileIO.findFile("jcolibri/test/recomendador/datos/databaseconfig.xml"));
                 _caseBase = new PearsonMatrixCaseBase(new Attribute("rating", Rating.class), 20);
                 accesoBBDD=new AccesoBBDD(_connector); 
                 /** KNN configuration*/
                simConfig=new NNConfig();
              //definimos las funciones de similitudo global y local
             	simConfig.setDescriptionSimFunction(new Average());
             	simConfig.addMapping(new Attribute("genreUnknown", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreAction", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreAdventure", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreAnimation", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreChildren", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreComedy", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreCrime", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreDocumentary", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreDrama", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreFantasy", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreFilmNoir", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreHorror", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreMusical", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreMystery", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreRomance", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreSciFi", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreThriller", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreWar", Movie.class), new Equal());
             	simConfig.addMapping(new Attribute("genreWestern", Movie.class), new Equal());
               	simConfig.addMapping(new Attribute("releaseDate", Movie.class), new IntervaloFechas(5));
        }

        @Override
        public void cycle(CBRQuery query) throws ExecutionException {
                
            Collection<RetrievalResult> res = CollaborativeRetrievalMethod.getRecommendation(_caseBase, query, 10);
            Collection<CBRCase> casesTodos =SelectCases.selectAll(res);
            Collection<CBRCase> peliculas=accesoBBDD.invertirDescriptionYSolution(casesTodos);
     		UserIdent u=(UserIdent)query.getDescription();
            Recomendacion.getInstancia(peliculas,u);
		}

        public boolean logeo(Integer s){
        	boolean existe=accesoBBDD.existeUsuario(s);
        	if (existe){
                        try {
                                Recomienda.getInstancia().accesoBBDD.creaVistaRating();
                                Recomienda.getInstancia().preCycle();
                                Inicio.getInstancia().setVisible(false);
                                CBRQuery query = new CBRQuery();
                                u=new UserIdent();
                                u.setId(s);
                                query.setDescription(u);
                            cycle(query);
                        }
                        catch (Exception e){
                                org.apache.commons.logging.LogFactory.getLog(Recomienda.class).error(e);
                                ConfigurableHSQLDBserver.shutDown();
                        }
            }else{
                   System.out.println("El usuarios no existe");
            }
        	return existe;
        }
        
        @Override
        public void postCycle() throws ExecutionException {
                // TODO Auto-generated method stub
                
        }

        @Override
        public CBRCaseBase preCycle() throws ExecutionException {
                // Load cases from connector into the case base
                _caseBase.init(_connector);             
                // Print the cases
                java.util.Collection<CBRCase> cases = _caseBase.getCases();
//              for(CBRCase c: cases)
//                      System.out.println(c);
                org.apache.commons.logging.LogFactory.getLog(this.getClass()).info(cases.size() +" cases loaded");
                return _caseBase;
        }


        public void acabando(){
                try{
                        Recomienda.getInstancia().postCycle();
                        ConfigurableHSQLDBserver.shutDown();
                }catch (Exception e)
                        {
                            org.apache.commons.logging.LogFactory.getLog(Recomienda.class).error(e);
                        }
        }
                   
        public Movie peliRandom(){
           Movie m;
           int max=accesoBBDD.maximoIdDeMovie();
           m=accesoBBDD.devuelvePeliculaAlAzar(max);
           return m;
        }
        
        public boolean ratearPelculas(ArrayList<Rateo> m){
        	return (accesoBBDD.ratearPeliculas(m));
        }
        
        public int nuevoUsuario(User u,ArrayList<Rateo> m){
                int id=accesoBBDD.altaUsuario(u);
                for (int i=0; i < m.size(); i++){
                        m.get(i).setIdUser(id);
                }
                if (accesoBBDD.ratearPeliculas(m))
                        return id;
                else
                        return -1;
        }
        
        public void masComoEsta(int idMovie, Collection<CBRCase> casos,UserIdent u){
        	Movie m=accesoBBDD.devuelvePelicula(idMovie);
        	CBRQuery query=new CBRQuery();
        	query.setDescription(m);
        	// Execute NN
        	Collection<RetrievalResult> retrievedCases = NNScoringMethod.evaluateSimilarity(casos, query, simConfig);
        	// Select cases
        	Collection<CBRCase> peliculas = SelectCases.selectAll(retrievedCases);
            Recomendacion.getInstancia(peliculas,u);
        }
        
        public User obtenerUsuario(UserIdent u){
        	User user=accesoBBDD.devuelveUsuario(u.getId());
        	return user;
        }
        
        public static void main(String[] args) {

                //SwingProgressBar shows the progress
                jcolibri.util.ProgressController.clear();
                jcolibri.util.ProgressController.register(new jcolibri.test.main.SwingProgressBar(), MatrixCaseBase.class);
                try
                {                       
                        ConfigurableHSQLDBserver.initInFileSystem("peliculas",true,"jcolibri/test/recomendador/datos");  // Create a data base connector
                        Recomienda.getInstancia().configure();
                        Inicio.getInstancia();
                } catch (Exception e)
                {
                    org.apache.commons.logging.LogFactory.getLog(Recomienda.class).error(e);
                    ConfigurableHSQLDBserver.shutDown();
                }
        }
}
